#ifndef AER_SAMPLER_HPP_
#define AER_SAMPLER_HPP_

#include "aerDeviceResource.hpp"
#include "aerTexture.hpp"


namespace aer {
  
class Sampler : public DeviceResource
{  
  private:
    static Sampler* sCurrent;
  
  
  private:
    GLuint m_unit;
  
  
  public:
    static Sampler* GetCurrent()
    {
      AER_ASSERT( sCurrent != NULLPTR );
      return sCurrent;
    }
    
    
  public:
    void generate()
    {
      AER_ASSERT( !isGenerated() );
      glGenSamplers( 1, &m_id);
    }
    
    void release()
    {
      if (isGenerated()) 
      {
        glDeleteSamplers( 1, &m_id);
        m_id = 0u;
      }
    }
    
    void bind(unsigned int unit=0u)
    {
      AER_ASSERT( isGenerated() );
      
      sCurrent = this;
      m_unit = GL_TEXTURE0 + unit;
      glBindSampler( m_unit, m_id);
    }
    
    void unbind()
    {
      sCurrent = NULLPTR;
      glBindSampler( m_unit, 0u );
    }
    


    // ==============
    // + Parameters +
    // ==============

    void setWrap( Texture::WrapTarget target, Texture::WrapMode mode)
    {
      glSamplerParameteri( m_id, target, mode);
    }
    
    void setWraps( Texture::WrapMode wrapS, 
                   Texture::WrapMode wrapT = Texture::REPEAT, 
                   Texture::WrapMode wrapR = Texture::REPEAT)
    {
      setWrap( GL_TEXTURE_WRAP_S, wrapS);
      setWrap( GL_TEXTURE_WRAP_T, wrapT);
      setWrap( GL_TEXTURE_WRAP_R, wrapR);
    }
    
    
    void setFilter( Texture::FilterTarget target, Texture::FilterMode mode)
    {
      glSamplerParameteri( m_id, target, mode);
    }
    
    void setFilters( Texture::FilterMode minMode, Texture::FilterMode magMode)
    {
      glSamplerParameteri( m_id, GL_TEXTURE_MIN_FILTER, minMode);
      glSamplerParameteri( m_id, GL_TEXTURE_MAG_FILTER, magMode);
    }
    
    void setMipmapFilter( Texture::FilterMode choice, Texture::FilterMode interpolation)
    {
      GLenum mode = Texture::GetMipmapMode( choice, interpolation);
      glSamplerParameteri( m_id, GL_TEXTURE_MIN_FILTER, mode);
    }
    
    
    void setCompareFunc(Texture::CompareFunc func)
    {
      glSamplerParameteri( m_id, GL_TEXTURE_COMPARE_MODE, mode);      
    }
    
    void setCompareMode(Texture::CompareMode mode)
    {
      glSamplerParameteri( m_id, GL_TEXTURE_COMPARE_MODE, mode);      
    }
    
    
    void setLOD( const float minLOD, const float maxLOD, const float bias=0.0f)
    {
      setMinLOD( minLOD );
      setMaxLOD( maxLOD );
      setLODBias( bias );
    }
    
    void setMinLOD(const float lod)
    {
      glSamplerParameterf( m_id, GL_TEXTURE_MIN_LOD, lod);
    }
    
    void setMaxLOD(const float lod)
    {
      glSamplerParameterf( m_id, GL_TEXTURE_MAX_LOD, lod);
    }
    
    void setLODBias(const float bias)
    {
      glSamplerParameterf( m_id, GL_TEXTURE_LOD_BIAS, bias);
    }
    
    
    void setBorderColor( const float r, const float g, const float b)
    {
      const GLfloat color[] = { r, g, b};
      glSamplerParameterfv( m_id, GL_TEXTURE_BORDER_COLOR, color);
    }
    
    
    // ===========
    // + Getters +
    // ===========
    // TODO
};

}

#endif // AER_SAMPLER_HPP_
